home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / arpadate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  10.2 KB  |  504 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)arpadate.c    5.11 (Berkeley) 6/1/90";
  23. static char rcsid[] = "@(#)$Id: arpadate.c,v 5.11.0.10 1991/06/28 05:52:38 paul Exp $";
  24. #endif /* not lint */
  25.  
  26. #include "sendmail.h"
  27.  
  28. /*
  29. **  ARPADATE -- Create date in ARPANET format
  30. **
  31. **    Parameters:
  32. **        ud -- unix style date string.  if NULL, one is created.
  33. **
  34. **    Returns:
  35. **        pointer to an ARPANET date field
  36. **
  37. **    Side Effects:
  38. **        none
  39. **
  40. **    WARNING:
  41. **        date is stored in a local buffer -- subsequent
  42. **        calls will overwrite.
  43. **
  44. **    Bugs:
  45. **        Timezone is computed from local time, rather than
  46. **        from whereever (and whenever) the message was sent.
  47. **        To do better is very hard.
  48. **
  49. **        Some sites are now inserting the timezone into the
  50. **        local date.  This routine should figure out what
  51. **        the format is and work appropriately.
  52. */
  53.  
  54. char *
  55. arpadate(ud)
  56.     register char *ud;
  57. {
  58.     register char *p;
  59.     register char *q;
  60.     register int off;
  61.     register struct tm *lt;
  62.     TIME_TYPE t;
  63.     struct tm gmt;
  64.     static char b[42];
  65.  
  66.     /*
  67.     **  Get current time.
  68.     **    This will be used if a null argument is passed and
  69.     **    to resolve the timezone.
  70.     */
  71.  
  72.     (void) time(&t);
  73.     if (ud == NULL)
  74.         ud = ctime(&t);
  75.  
  76.     /*
  77.     **  Crack the UNIX date line in a singularly unoriginal way.
  78.     */
  79.  
  80.     q = b;
  81.  
  82.     p = &ud[0];        /* Mon */
  83.     *q++ = *p++;
  84.     *q++ = *p++;
  85.     *q++ = *p++;
  86.     *q++ = ',';
  87.     *q++ = ' ';
  88.  
  89.     p = &ud[8];        /* 16 */
  90.     if (*p == ' ')
  91.         p++;
  92.     else
  93.         *q++ = *p++;
  94.     *q++ = *p++;
  95.     *q++ = ' ';
  96.  
  97.     p = &ud[4];        /* Sep */
  98.     *q++ = *p++;
  99.     *q++ = *p++;
  100.     *q++ = *p++;
  101.     *q++ = ' ';
  102.  
  103.     p = &ud[20];        /* 1979  or _1979 */
  104.     if (*p == ' ')
  105.         p++;
  106.     *q++ = *p++;
  107.     *q++ = *p++;
  108.     *q++ = *p++;
  109.     *q++ = *p++;
  110.     *q++ = ' ';
  111.  
  112.     p = &ud[11];        /* 01:03:52 or 01:03 EST */
  113.     *q++ = *p++;
  114.     *q++ = *p++;
  115.     *q++ = *p++;
  116.     *q++ = *p++;
  117.     *q++ = *p++;
  118.     if (*p == ':')
  119.     {
  120.         *q++ = *p++;
  121.         *q++ = *p++;
  122.         *q++ = *p++;
  123.     }
  124.  
  125.     /*
  126.      * should really get the timezone from the time in "ud" (which
  127.      * is only different if a non-null arg was passed which is different
  128.      * from the current time), but for all practical purposes, returning
  129.      * the current local zone will do (its all that is ever needed).
  130.      */
  131.     gmt = *gmtime(&t);
  132.     lt = localtime(&t);
  133.  
  134.     off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
  135.  
  136.     /* assume that offset isn't more than a day ... */
  137.     if (lt->tm_year < gmt.tm_year)
  138.         off -= 24 * 60;
  139.     else if (lt->tm_year > gmt.tm_year)
  140.         off += 24 * 60;
  141.     else if (lt->tm_yday < gmt.tm_yday)
  142.         off -= 24 * 60;
  143.     else if (lt->tm_yday > gmt.tm_yday)
  144.         off += 24 * 60;
  145.  
  146.     *q++ = ' ';
  147.     if (off == 0)
  148.     {
  149.         *q++ = 'G';
  150.         *q++ = 'M';
  151.         *q++ = 'T';
  152.     }
  153.     else
  154.     {
  155.         if (off < 0)
  156.         {
  157.             off = -off;
  158.             *q++ = '-';
  159.         }
  160.         else
  161.             *q++ = '+';
  162.  
  163.         if (off >= 24*60)        /* should be impossible */
  164.             off = 23*60+59;        /* if not, insert silly value */
  165.  
  166.         *q++ = (off / 600) + '0';
  167.         *q++ = (off / 60) % 10 + '0';
  168.         off %= 60;
  169.         *q++ = (off / 10) + '0';
  170.         *q++ = (off % 10) + '0';
  171.     }
  172.     *q = '\0';
  173.  
  174.     return(b);
  175. }
  176. /*
  177. **  NEXTATOM -- Return pointer to next atom in header
  178. **        (skip whitespace and comments)
  179. **
  180. **    Parameters:
  181. **        s -- pointer to header string
  182. **
  183. **    Returns:
  184. **        pointer advanced to next non-comment header atom
  185. **
  186. **    Side Effects:
  187. **        none
  188. */
  189.  
  190. static char *
  191. nextatom(s)
  192.     char *s;
  193. {
  194.     char *p;
  195.  
  196.     for (p = s;
  197.          *p && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '(');
  198.          p++)
  199.     {
  200.         if (*p == '(')
  201.         {
  202.             int nested = 0;
  203.  
  204.             /* ignore comments */
  205.             p++;
  206.             for (; *p; p++)
  207.             {
  208.                 if (*p == '(')
  209.                     nested++;
  210.                 else if (*p == ')')
  211.                     if (!nested)
  212.                         break;
  213.                     else
  214.                         nested--;
  215.             }
  216.         }
  217.     }
  218.     return (p);
  219. }
  220.  
  221. /*
  222. **  ARPATOUNIX -- Convert RFC-822/1123 date-time specification to
  223. **        UNIX(R) ctime format.
  224. **
  225. **    Parameters:
  226. **        s -- pointer to date string
  227. **        e -- pointer to envelope associated with date
  228. **
  229. **    Returns:
  230. **        pointer to a string in ctime format
  231. **
  232. **    Side Effects:
  233. **        Calls asctime() which modifies its static area.
  234. */
  235.  
  236. /*
  237. ** date-time field specification from RFC822 as amended by RFC 1123:
  238. **
  239. **
  240. ** [ day "," ] 1*2DIGIT month 2*4DIGIT 2DIGIT ":" 2DIGIT [ ":" 2DIGIT  ] zone
  241. **         date        year    hours      minutes      seconds
  242. **
  243. ** day can be "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun" (case-insensitive)
  244. **
  245. ** month can be "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct"
  246. ** "Nov" "Dec" (also case-insensitive)
  247. **
  248. ** zone can be "UT" "GMT" "EST" "EDT" "CST" "CDT" "MST" "MDT" "PST" "PDT"
  249. ** or "+"4*DIGIT or "-"4*DIGIT (case-insensitive; military zones not useful
  250. ** per RFC1123)
  251. **
  252. ** Additional whitespace or comments may occur.
  253. */
  254.  
  255. static char MonthDays[] = {
  256.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  257. };
  258.  
  259. char *
  260. arpatounix(s, e)
  261.     char    *s;
  262.     ENVELOPE *e;
  263. {
  264.     struct tm tm;
  265.     char    *p;
  266.     int    h_offset = 0;        /* hours */
  267.     int    m_offset = 0;        /* minutes */
  268.     extern char *DowList[];        /* defined in collect.c */
  269.     extern char *MonthList[];    /* defined in collect.c */
  270.  
  271.     bzero((char *) &tm, sizeof tm);
  272.     tm.tm_wday = -1;    /* impossible value */
  273.     p = nextatom (s);
  274.  
  275.     /* next atom must be a day or a date */
  276.     if (isalpha((int) *p))
  277.     {
  278.         /* day */
  279.         for (tm.tm_wday = 0; DowList[tm.tm_wday]; tm.tm_wday++)
  280.             if (strncasecmp (p, DowList[tm.tm_wday], 3))
  281.                 continue;
  282.             else
  283.             {
  284.                 p += 3;
  285.                 break;
  286.             }
  287.         p = nextatom(p);        /* ',' */
  288.         if (*p == ',')
  289.             p = nextatom(++p);
  290.     }
  291.  
  292.     /* now must have date */
  293.     tm.tm_mday = atoi(p);
  294.     while (isdigit((int) *p))        /* skip over date */
  295.         p++;
  296.     p = nextatom(p);            /* point to month name */
  297.     for (tm.tm_mon = 0; MonthList[tm.tm_mon]; tm.tm_mon++)
  298.         if (strncasecmp(p, MonthList[tm.tm_mon], 3))
  299.             continue;
  300.         else {
  301.             p += 3;
  302.             break;
  303.         }
  304.  
  305.     p = nextatom(p);            /* year */
  306.     tm.tm_year = atoi(p);
  307.  
  308.     /* if this was 4 digits, subtract 1900 */
  309.     if (tm.tm_year > 999)
  310.         tm.tm_year -= 1900;
  311.     else
  312.     {
  313.         /* if 2 or 3 digits, guess which century and convert */
  314.         TIME_TYPE now;
  315.         struct tm *gmt;
  316.  
  317.         (void) time(&now);
  318.         gmt = gmtime(&now);
  319.  
  320.         /* more likely +1 day than -100(0) years */
  321.         if (gmt->tm_mon == 11 && gmt->tm_mday == 31 &&
  322.             tm.tm_mon == 0 && tm.tm_mday == 1)
  323.             gmt->tm_year++;
  324.         if (tm.tm_year > 99)
  325.         {
  326.             /* 3 digits */
  327.             tm.tm_year += ((gmt->tm_year + 900 - tm.tm_year) / 1000) * 1000;
  328.         }
  329.         else
  330.         {
  331.             /* 2 digits */
  332.             tm.tm_year += ((gmt->tm_year - tm.tm_year) / 100) * 100;
  333.         }
  334.     }
  335.     while (isdigit((int) *p))    /* skip over year */
  336.         p++;
  337.     p = nextatom(p);        /* hours */
  338.     tm.tm_hour = atoi(p);
  339.     while (isdigit((int) *p))    /* skip over hours */
  340.         p++;
  341.     p = nextatom(p);        /* colon */
  342.     if (*p == ':')
  343.         p = nextatom(++p);
  344.     p = nextatom(p);        /* minutes */
  345.     tm.tm_min = atoi(p);
  346.     while (isdigit((int) *p))    /* skip over minutes */
  347.         p++;
  348.     p = nextatom(p);        /* colon or zone */
  349.     if (*p == ':')            /* have seconds field */
  350.     {
  351.         p = nextatom(++p);
  352.         tm.tm_sec = atoi(p);
  353.         while (isdigit((int) *p))    /* skip over seconds */
  354.             p++;
  355.     }
  356.     p = nextatom(p);        /* zone */
  357.     if (!strncasecmp(p, "UT", 2) || !strncasecmp(p, "GMT", 3))
  358.         ;
  359.     else if (!strncasecmp(p, "EDT", 3))
  360.         h_offset = -4;
  361.     else if (!strncasecmp(p, "EST", 3))
  362.     {
  363.         h_offset = -5;
  364.         tm.tm_isdst = 1;
  365.     }
  366.     else if (!strncasecmp(p, "CDT", 3))
  367.         h_offset = -5;
  368.     else if (!strncasecmp(p, "CST", 3))
  369.     {
  370.         h_offset = -6;
  371.         tm.tm_isdst = 1;
  372.     }
  373.     else if (!strncasecmp(p, "MDT", 3))
  374.         h_offset = -6;
  375.     else if (!strncasecmp(p, "MST", 3))
  376.     {
  377.         h_offset = -7;
  378.         tm.tm_isdst = 1;
  379.     }
  380.     else if (!strncasecmp(p, "PDT", 3))
  381.         h_offset = -7;
  382.     else if (!strncasecmp(p, "PST", 3))
  383.     {
  384.         h_offset = -8;
  385.         tm.tm_isdst = 1;
  386.     }
  387.     else if (*p == '+')
  388.     {
  389.         int off;
  390.  
  391.         off = atoi(++p);
  392.         h_offset = off / 100;
  393.         m_offset = off % 100;
  394.     }
  395.     else if (*p == '-')
  396.     {
  397.         int off;
  398.  
  399.         off = atoi(++p);
  400.         h_offset = off / -100;
  401.         m_offset = -1 * (off % 100);
  402.     }
  403.     else
  404.     {
  405. #ifdef LOG
  406.         syslog(LOG_NOTICE, "%s: arpatounix: unparseable date: %s",
  407.             e->e_id, s);
  408. #endif /* LOG */
  409.         return(NULL);
  410.     }
  411.  
  412.     /* is the year a leap year? */
  413.     if ((tm.tm_year % 4 == 0) &&
  414.         ((tm.tm_year % 100 != 0) || (tm.tm_year % 400 == 0)))
  415.         MonthDays[2] = 29;
  416.     else
  417.         MonthDays[2] = 28;
  418.  
  419.     /* apply offset */
  420.     if (h_offset || m_offset)
  421.     {
  422.         tm.tm_min += m_offset;
  423.         tm.tm_hour += h_offset;
  424.  
  425.         /* normalize */
  426.         if (tm.tm_min < 0)
  427.         {
  428.             tm.tm_hour--;
  429.             tm.tm_min += 60;
  430.         }
  431.         else if (tm.tm_min > 59)
  432.         {
  433.             tm.tm_hour++;
  434.             tm.tm_min -= 60;
  435.         }
  436.         if (tm.tm_hour < 0)
  437.         {
  438.             tm.tm_mday--;
  439.             tm.tm_wday--;
  440.             tm.tm_hour += 24;
  441.         }
  442.         else if (tm.tm_hour > 23)
  443.         {
  444.             tm.tm_mday++;
  445.             tm.tm_wday++;
  446.             tm.tm_hour -= 24;
  447.         }
  448.         if (tm.tm_mday < 1)
  449.         {
  450.             if (--tm.tm_mon == -1)
  451.             {
  452.                 tm.tm_mon = 11;
  453.                 tm.tm_year--;
  454.  
  455.                 /* is the year a leap year? */
  456.                 if ((tm.tm_year % 4 == 0) &&
  457.                     ((tm.tm_year % 100 != 0) || (tm.tm_year % 400 == 0)))
  458.                     MonthDays[2] = 29;
  459.                 else
  460.                     MonthDays[2] = 28;
  461.             }
  462.             tm.tm_mday += MonthDays[tm.tm_mon];
  463.         }
  464.         else if (tm.tm_mday > MonthDays[tm.tm_mon])
  465.         {
  466.             tm.tm_mday -= MonthDays[tm.tm_mon++];
  467.             if (tm.tm_mon > 11)
  468.             {
  469.                 tm.tm_mon = 0;
  470.                 tm.tm_year++;
  471.  
  472.                 /*
  473.                 * Don't have to worry about leap years in
  474.                 * January.
  475.                 */
  476.             }
  477.         }
  478.     }
  479.  
  480.     /* determine day of week if not set from RFC822/1123 line */
  481.     if (tm.tm_wday < 0)
  482.     {
  483.         int i;
  484.  
  485.         for (i = 0; i < tm.tm_mon; i++)
  486.             tm.tm_yday += MonthDays[i];
  487.         tm.tm_yday += tm.tm_mday;
  488.  
  489.         /* I wouldn't change these constants if I were you... */
  490.         tm.tm_wday = (int) (((((tm.tm_year + 699L) * 146097L) / 400L) + tm.tm_yday) % 7);
  491.     }
  492.  
  493.     /* now get UT */
  494.     if ((p = asctime(&tm)) == NULL || *p == '\0' || strlen(p) < 25)
  495.     {
  496. #ifdef LOG
  497.         syslog(LOG_NOTICE, "%s: arpatounix: asctime failed: %s",
  498.             e->e_id, s);
  499. #endif /* LOG */
  500.         return(NULL);
  501.     }
  502.     return(p);
  503. }
  504.